package com.jfirer.mvc.binder.impl;

import com.jfirer.baseutil.reflect.ReflectUtil;
import com.jfirer.mvc.binder.ContainerBinder;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ListBinder implements ContainerBinder
{
    private String          prefix;
    private Class           listClass;
    private Class           componentClass;
    private ContainerBinder containerBinder;
    private int             prefixLength;

    public ListBinder(String prefix, Type type)
    {
        this.prefix = prefix;
        prefixLength = prefix.length();
        if (type instanceof ParameterizedType == false)
        {
            throw new IllegalArgumentException();
        }
        listClass = (Class) ((ParameterizedType) type).getRawType();
        if (listClass.isInterface())
        {
            listClass = ArrayList.class;
        }
        componentClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
    }

    @Override
    public Object bind(String name, String[] value, Object mayExistContainer)
    {
        List list = null;
        try
        {
            list = (List) (mayExistContainer == null ? listClass.newInstance() : mayExistContainer);
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
        }
        if (name.charAt(prefixLength + 1) == ']')
        {
            if (componentClass == Integer.class)
            {
                for (String each : value)
                {
                    list.add(Integer.valueOf(each));
                }
            }
            else if (componentClass == Byte.class)
            {
                for (String each : value)
                {
                    list.add(Byte.valueOf(each));
                }
            }
            else if (componentClass == Short.class)
            {
                for (String each : value)
                {
                    list.add(Short.valueOf(each));
                }
            }
            else if (componentClass == Long.class)
            {
                for (String each : value)
                {
                    list.add(Long.valueOf(each));
                }
            }
            else if (componentClass == Boolean.class)
            {
                for (String each : value)
                {
                    list.add(Boolean.valueOf(each));
                }
            }
            else if (componentClass == Float.class)
            {
                for (String each : value)
                {
                    list.add(Float.valueOf(each));
                }
            }
            else if (componentClass == Double.class)
            {
                for (String each : value)
                {
                    list.add(Double.valueOf(each));
                }
            }
            else if (componentClass == Character.class)
            {
                for (String each : value)
                {
                    list.add(each.charAt(0));
                }
            }
            else if (componentClass == String.class)
            {
                for (String each : value)
                {
                    list.add(each);
                }
            }
            else
            {
                throw new IllegalArgumentException("数组不匹配这种模式");
            }
        }
        else
        {
            bind(name, value[0], list);
        }
        return list;
    }

    @Override
    public Object bind(String name, String value, Object mayExistContainer)
    {
        List list = null;
        try
        {
            list = (List) (mayExistContainer == null ? listClass.newInstance() : mayExistContainer);
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
        }
        if (name.charAt(prefixLength + 1) == ']')
        {
            if (componentClass == Integer.class)
            {
                list.add(Integer.valueOf(value));
            }
            else if (componentClass == Byte.class)
            {
                list.add(Byte.valueOf(value));
            }
            else if (componentClass == Short.class)
            {
                list.add(Short.valueOf(value));
            }
            else if (componentClass == Long.class)
            {
                list.add(Long.valueOf(value));
            }
            else if (componentClass == Boolean.class)
            {
                list.add(Boolean.valueOf(value));
            }
            else if (componentClass == Float.class)
            {
                list.add(Float.valueOf(value));
            }
            else if (componentClass == Double.class)
            {
                list.add(Double.valueOf(value));
            }
            else if (componentClass == Character.class)
            {
                list.add(value.charAt(0));
            }
            else if (componentClass == String.class)
            {
                list.add(value);
            }
            else
            {
                throw new IllegalArgumentException("数组不匹配这种模式");
            }
        }
        else
        {
            int end   = name.indexOf(']', prefixLength);
            int index = Integer.parseInt(name.substring(prefixLength + 1, end));
            int left  = index - list.size() + 1;
            for (int i = 0; i < left; i++)
            {
                list.add(null);
            }
            if (componentClass == Integer.class)
            {
                list.set(index, Integer.valueOf(value));
            }
            else if (componentClass == Byte.class)
            {
                list.set(index, Byte.valueOf(value));
            }
            else if (componentClass == Short.class)
            {
                list.set(index, Short.valueOf(value));
            }
            else if (componentClass == Long.class)
            {
                list.set(index, Long.valueOf(value));
            }
            else if (componentClass == Boolean.class)
            {
                list.set(index, Boolean.valueOf(value));
            }
            else if (componentClass == Float.class)
            {
                list.set(index, Float.valueOf(value));
            }
            else if (componentClass == Double.class)
            {
                list.set(index, Double.valueOf(value));
            }
            else if (componentClass == Character.class)
            {
                list.set(index, value.charAt(0));
            }
            else if (componentClass == String.class)
            {
                list.set(index, value);
            }
            else
            {
                ContainerBinder containerBinder = this.containerBinder;
                if (containerBinder == null)
                {
                    if (componentClass.isArray())
                    {
                        this.containerBinder = containerBinder = new ArrayBinder2("", componentClass);
                    }
                    else if (List.class.isAssignableFrom(componentClass))
                    {
                        throw new UnsupportedOperationException("不支持连续的List泛型的参数绑定");
                    }
                    else
                    {
                        this.containerBinder = containerBinder = new BeanBinder2("", componentClass);
                    }
                }
                String subName = name.substring(end + 1);
                Object element = list.get(index);
                element = containerBinder.bind(subName, value, element);
                list.set(index, element);
            }
        }
        return list;
    }

    @Override
    public Object bindMulti(Map<String, String[]> map)
    {
        List list;
        try
        {
            list = (List) listClass.newInstance();
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
            return null;
        }
        for (Map.Entry<String, String[]> each : map.entrySet())
        {
            String key = each.getKey();
            if (key.startsWith(prefix) && key.charAt(prefixLength) == '[')
            {
                bind(key, each.getValue(), list);
            }
        }
        return list;
    }

    @Override
    public Object bind(Map<String, String> map)
    {
        List list;
        try
        {
            list = (List) listClass.newInstance();
        }
        catch (Exception e)
        {
            ReflectUtil.throwException(e);
            return null;
        }
        for (Map.Entry<String, String> each : map.entrySet())
        {
            String key = each.getKey();
            if (key.startsWith(prefix) && key.charAt(prefixLength) == '[')
            {
                bind(key, each.getValue(), list);
            }
        }
        return list;
    }
}
